package com.tianji.learning.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.po.PointsRecord;
import com.tianji.learning.domain.vo.PointsStatisticsVO;
import com.tianji.learning.enums.PointsRecordType;
import com.tianji.learning.mapper.PointsRecordMapper;
import com.tianji.learning.service.IPointsRecordService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static com.tianji.learning.constans.SignRecordConstans.POINTS_BOARD_KEY_PRIFIX;

/**
 * <p>
 * 学习积分记录，每个月底清零 服务实现类
 * </p>
 *
 * @author wxh
 * @since 2024-08-29
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PointsRecordServiceImpl extends ServiceImpl<PointsRecordMapper, PointsRecord> implements IPointsRecordService {
    private final StringRedisTemplate redisTemplate;

    /**
     * 学习问答积分消费
     *
     * @param userId 用户id
     * @param point  积分
     * @param type   获取积分的类型
     */
    @Override
    public void addPointsRecords(Long userId, int point, PointsRecordType type) {
        //1.判断该渠道获取的积分是否有上限
        //1.1.积分的上限
        int maxPoints = type.getMaxPoints();
        //1.2判断最大积分上限是否大于0,大于0说明有积分上限
        if (maxPoints > 0) {
            //2.有上限则查询【今日】已获取的积分
            //select sum(points) as points from points_record where user_id = 2 and type = 3 and
            //create_time between '2023-02-14 19:19:11' and ' 2023-02-14 23:39:11';
            //2.1获取当天的开始时间和结束时间
            LocalDateTime now = LocalDateTime.now();
            LocalDateTime begin = DateUtils.getDayStartTime(now);
            LocalDateTime end = DateUtils.getDayEndTime(now);
            int queryPonts = quetyPoints(userId, type, begin, end);
            //3.判断是否超过积分上限
            if (queryPonts >= maxPoints) {
                return;
            }
            //3.1当前分数还没有超过上限，但是加上这次的分数就超过了，则需要加的是上限分数减去当前分数的差值
            if (queryPonts + point > maxPoints) {
                point = maxPoints - queryPonts;

            }
        }
        //4.保存积分到积分记录表
        PointsRecord pointsRecord = new PointsRecord().setPoints(point).setUserId(userId).setType(type);
        save(pointsRecord);

        //5.累加并保持总积分到redis中
        LocalDateTime now = LocalDateTime.now();
        //获取上个月
        now.minusMonths(1);
        //5.1组装大key
        String key = POINTS_BOARD_KEY_PRIFIX + now.format(DateUtils.DATE_SUFFIX_FORMATTER);
        Double isSuccess = redisTemplate.opsForZSet().incrementScore(key, userId.toString(), point);
        if (Boolean.FALSE.equals(isSuccess)) {
            log.error("总积分加入到zSet中失败");
        }
    }

    /**
     * 查询每日积分
     *
     * @return
     */
    @Override
    public List<PointsStatisticsVO> queryEveryPoint() {
        //0。获取userId
        Long userId = UserContext.getUser();
        //1.分页查询point_record表，根据获取积分类型进行分组
        //select `type`,sum(points) as points from points_record where user_id = 2 and
        //create_time between '2023-02-14 19:19:11' and ' 2023-02-14 23:39:11' group by type;
        //1.1获取今日的开始时间和结束时间
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime begin = DateUtils.getDayStartTime(now);
        LocalDateTime end = DateUtils.getDayEndTime(now);
        List<PointsRecord> pointRecordList = this.query().select("`type`,sum(points) as points")
                .eq("user_id", userId)
                .between("create_time", begin, end)
                .groupBy("`type`")
                .list();
        if (ObjectUtil.isEmpty(pointRecordList)) {
            //1.2查询为空则返回一个空集合
            return Collections.emptyList();
        }
        //2.遍历查出的数据进行数据分装
        //2.1创建一个voList
        List<PointsStatisticsVO> voList = new ArrayList<>(pointRecordList.size());
        pointRecordList.forEach(pointsRecord -> {
            //2.2.创建一个PointsStatisticsVO
            PointsStatisticsVO vo = new PointsStatisticsVO();
            //每日获取的分数
            vo.setPoints(pointsRecord.getPoints());
            //获取分数的渠道
            vo.setType(pointsRecord.getType().getDesc());
            //每日分数的上限
            vo.setMaxPoints(pointsRecord.getType().getMaxPoints());
            voList.add(vo);
        });
        //3。返回voList
        return voList;
    }

    /**
     * 查询今日已获得的积分
     *
     * @param userId
     * @param type
     * @param begin
     * @param end
     */
    private int quetyPoints(Long userId, PointsRecordType type, LocalDateTime begin, LocalDateTime end) {
        PointsRecord record = this.query().select("sum(points) as points")
                .eq("user_id", userId)
                .eq("`type`", PointsRecordType.QA)
                .eq("`type`", type)
                .between("create_time", begin, end)
                .one();
        return ObjectUtil.isEmpty(record) || ObjectUtil.isEmpty(record.getPoints()) ? 0 : record.getPoints();
    }


}
